﻿#if USING_XLUA
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using XLua;
using System;
using com.susi.util;
using static System.Diagnostics.Contracts.Contract;

namespace com.susi.Lua {
    [System.Serializable]
    public class Injection {
        public string     name;
        public GameObject value;
    }

    [LuaCallCSharp]
    public class LuaBehaviour : MonoBehaviour, IDisposaEventer, IDisposaEventer<LuaBehaviour> {
        public TextAsset   luaScript;
        public Injection[] injections;

        public bool IsDisposed { get; private set; }
        
        internal LuaEnv luaEnv = LuaManager.Instance.luaEnv; //all lua behaviour shared one luaenv only!

        private Action luaStart;
        private Action luaUpdate;
        private Action luaOnDestroy;

        private LuaTable scriptEnv;

        public event Action               onDisposingEvent;
        public event Action<LuaBehaviour> onDisposingTEvent;

        private void Awake()
        {
            scriptEnv = luaEnv.NewTable();

            // 为每个脚本设置一个独立的环境，可一定程度上防止脚本间全局变量、函数冲突
            LuaTable meta = luaEnv.NewTable();
            meta.Set("__index", luaEnv.Global);
            scriptEnv.SetMetaTable(meta);
            meta.Dispose();

            scriptEnv.Set("self", this);
            if (injections != null) {
                foreach (var injection in injections) {
                    scriptEnv.Set(injection.name, injection.value);
                }
            }

            Assert(luaScript, "luaScript can't be null");
            luaEnv.DoString(luaScript.text, "LuaTestScript", scriptEnv);

            Action luaAwake = scriptEnv.Get<Action>("awake");
            scriptEnv.Get("Start", out luaStart);
            scriptEnv.Get("Update", out luaUpdate);
            scriptEnv.Get("OnDestroy", out luaOnDestroy);

            if (luaAwake != null) luaAwake();
        }

        // Use this for initialization
        private void Start()
        {
            if (luaStart != null) luaStart();
        }

        // Update is called once per frame
        private void Update()
        {
            if (luaUpdate != null) luaUpdate();
        }

        private void OnDestroy()
        {
            Dispose();
        }

        public void Dispose()
        {
            if (IsDisposed) return;
            IsDisposed = true;
            if (luaOnDestroy != null) luaOnDestroy();
            
            onDisposingEvent?.Invoke();
            onDisposingTEvent?.Invoke(this);
            onDisposingEvent  = null;
            onDisposingTEvent = null;
            
            luaOnDestroy = null;
            luaUpdate    = null;
            luaStart     = null;
            scriptEnv.Dispose();
            injections = null;
        }
    }
}
#endif